import {
  Color,
  PolygonHierarchy,
  Cartesian3,
  HeadingPitchRange,
  CallbackProperty,
  Math as cesiumMath,
  Rectangle,
  NearFarScalar,
  ColorMaterialProperty,
  Transforms,
  Matrix4,
  Cartographic,
  Cartesian2,
  ImageMaterialProperty,
  LineFlowMaterialProperty,
  PolylineGlowMaterialProperty,
  PolylineDashMaterialProperty,
  PolylineTrailLinkMaterialProperty,
  CircleWaveMaterialProperty,
} from "cesium";
import {
  lngLatsToCartesian3Array,
  lngLatToCartesian3,
  lngLatValid,
} from "./coordinate";
import { setDefaultValue, isUndefined } from "./common";

export const callbackItem = ({ fn = () => {}, isConstant = false }) => {
  fn._generator = callback;
  fn.once = true;
  fn.isConstant = isConstant;
  return fn;
};

export const callback = function () {
  const { isConstant } = this;
  return new CallbackProperty(fn, isConstant);
};

/**
 * @name 根据lnglat生成三维坐标
 * @param {*} param0
 * @returns
 */
export const positionItem = ({ lng, lat, height }) => {
  lngLatValid(lng, lat);
  return {
    lng,
    lat,
    height: setDefaultValue(height, 0),
    _generator: position,
  };
};
export const position = function () {
  const { lng, lat, height } = this;
  return Cartesian3.fromDegrees(lng, lat, height);
};
/**
 * @name 根据lnglat数组生成三维坐标数组
 * @param {*} positionArr
 * @returns
 */
export const positionsItem = (positionArr = [], callback = false) => {
  positionArr = [...positionArr];
  positionArr._generator = positions;
  positionArr.once = positionArr._callback = callback;
  return positionArr;
};

export const positions = function () {
  return new CallbackProperty(() => {
    return this.map(lngLatToCartesian3);
  }, !this._callback);
};
/**
 * @name 虚线
 * @param {Object} obj
 * @param {String} obj.color 16进制颜色
 * @returns
 */
export const dashMaterialItem = ({ color, ...options } = {}) => {
  return {
    color: setDefaultValue(color, "rgba(0,175,255,0.9)"),
    ...options,
    _generator: dashMaterialProperty,
  };
};

export const dashMaterialProperty = function () {
  const { color, glowPower, taperPower, _callback } = this;
  if (!_callback) {
    return new PolylineDashMaterialProperty({
      color: Color.fromCssColorString(this.color),
      glowPower: this.glowPower,
      taperPower: this.taperPower,
    });
  }
  return new PolylineDashMaterialProperty(
    new CallbackProperty(() => {
      return {
        color: Color.fromCssColorString(this.color),
        glowPower: this.glowPower,
        taperPower: this.taperPower,
      };
      //   color: Color.fromCssColorString(this.color);
    }, false)
  );
};
/**
 * @name 发光线
 */
export const materialPropertyItem = ({ color, ...options } = {}) => {
  return {
    color: setDefaultValue(color, "rgba(0,175,255,0.9)"),
    ...options,
    _generator: materialProperty,
  };
};

export const materialProperty = function () {
  const { color, glowPower, taperPower, _callback } = this;
  if (!_callback) {
    return new PolylineGlowMaterialProperty({
      color: Color.fromCssColorString(this.color),
      glowPower: this.glowPower,
      taperPower: this.taperPower,
    });
  }
  return new PolylineGlowMaterialProperty(
    new CallbackProperty(() => {
      return {
        color: Color.fromCssColorString(this.color),
        glowPower: this.glowPower,
        taperPower: this.taperPower,
      };
      //   color: Color.fromCssColorString(this.color);
    }, false)
  );
};

/**
 * @name 添加图片材质
 * @param {String} image
 * @param {Array} repeat new Cartesian2(1.0, 1.0)
 * @param {String} color Color.WHITE
 * @param {String} transparent Color.WHITE
 */
export const materialImageMaterialPropertyItem = ({
  color,
  image,
  repeat,
  transparent,
  ...options
} = {}) => {
  return {
    image,
    repeat,
    color: setDefaultValue(color, "rgba(0,175,255,0.9)"),
    ...options,
    _generator: materialImageMaterialProperty,
  };
};

export const materialImageMaterialProperty = function () {
  const { color, image, repeat, transparent, _callback } = this;
  if (!_callback) {
    return new ImageMaterialProperty({
      color: Color.fromCssColorString(this.color),
      glowPower: this.glowPower,
      taperPower: this.taperPower,
      image: this.image,
      transparent: this.transparent,
      repeat: this.repeat,
      taperPower: this.taperPower,
    });
  }
  return new ImageMaterialProperty(
    new CallbackProperty(() => {
      return {
        color: Color.fromCssColorString(this.color),
        image: this.image,
        transparent: this.transparent,
        repeat: this.repeat,
        taperPower: this.taperPower,
      };
    }, false)
  );
};

/**
 * @name 添加流动材质
 * @param {String} image
 * @param {String} color Color.WHITE
 * @param {String} duration 时间
 */
export const materialPolylineTrailLinkMaterialPropertyItem = ({
  color,
  image,
  duration,
  ...options
} = {}) => {
  return {
    image: setDefaultValue(image, "/bx-dashboard/imgs/cz.png"),
    duration: setDefaultValue(duration, 4000),
    color: setDefaultValue(color, "rgba(0,175,255,0.9)"),
    ...options,
    _generator: materialPolylineTrailLinkMaterialProperty,
  };
};

export const materialPolylineTrailLinkMaterialProperty = function () {
  const { color, image, duration, transparent, _callback } = this;
  if (!_callback) {
    return new PolylineTrailLinkMaterialProperty({
      color: Color.fromCssColorString(this.color),
      image: this.image,
      duration: this.duration,
    });
  }
  return new PolylineTrailLinkMaterialProperty(
    new CallbackProperty(() => {
      return {
        color: Color.fromCssColorString(this.color),
        image: this.image,
        duration: this.duration,
        repeat: this.repeat,
        taperPower: this.taperPower,
      };
    }, false)
  );
};

/**
 * @name 添加圆点扩散材质
 * @param {String} height  高度
 * @param {String} semiMinorAxis  长半轴
 * @param {String} semiMajorAxis  短半轴
 * @param {String} color Color.WHITE
 * @param {Number} duration 速度
 * @param {String} gradient 渐变
 * @param {String} count 数量
 */
export const materialCircleWaveMaterialItem = ({
  color,
  height,
  duration,
  gradient,
  count,
  ...options
} = {}) => {
  return {
    height: setDefaultValue(height, 0),
    duration: setDefaultValue(duration, 5000.0),
    gradient: setDefaultValue(gradient, 0.5),
    count: setDefaultValue(count, 1),
    color: setDefaultValue(color, "rgba(0,175,255,0.9)"),
    ...options,
    _generator: materialCircleWaveMaterial,
  };
};

export const materialCircleWaveMaterial = function () {
  const {
    color,
    height,
    semiMinorAxis,
    semiMajorAxis,
    duration,
    gradient,
    count,
    _callback,
  } = this;
  if (!_callback) {
    return new CircleWaveMaterialProperty({
      color: Color.fromCssColorString(this.color),
      height: this.height,
      duration: this.duration,
      gradient: this.gradient,
      count: this.count,
    });
  }
  return new CircleWaveMaterialProperty(
    new CallbackProperty(() => {
      return {
        color: Color.fromCssColorString(this.color),
        height: this.height,
        duration: this.duration,
        gradient: this.gradient,
        count: this.count,
      };
    }, false)
  );
};

/**
 * @name 创建飞线
 * @param {Object} obj
 * @param {String} obj.color 16进制颜色
 * @param {String} obj.speed 速度
 * @returns
 */
export const lineFlowMaterialItem = ({ color, ...options } = {}) => {
  return {
    color: setDefaultValue(color, "rgba(255,0,0,0.5)"),
    speed: 4,
    ...options,
    _generator: lineFlowMaterial,
  };
};

export const lineFlowMaterial = function () {
  const { color, speed, _callback } = this;
  if (!_callback) {
    return new LineFlowMaterialProperty({
      color: Color.fromCssColorString(this.color),
      speed: this.speed,
      percent: 0.1,
      gradient: 0.01,
    });
  }
  return new LineFlowMaterialProperty(
    new CallbackProperty(() => {
      return {
        color: Color.fromCssColorString(this.color),
        speed: this.speed,
        percent: 0.1,
        gradient: 0.01,
      };
    }, false)
  );
};

/**
 * @name 根据颜色对象生成材质
 * @param {Object} obj
 * @param {String} obj.color 16进制颜色
 * @returns
 */

export const materialColorItem = ({ color, ...options } = {}) => {
  return {
    color: setDefaultValue(color, "rgba(255,0,0,0.5)"),
    ...options,
    _generator: materialColor,
  };
};

export const materialColor = function () {
  const { color, _callback } = this;
  if (!_callback) {
    return Color.fromCssColorString(this.color);
  }
  return new ColorMaterialProperty(
    new CallbackProperty(() => {
      return Color.fromCssColorString(this.color);
    }, false)
  );
};

/**
 * @name 根据层级对象生成层级
 * @param {Object} obj
 * @param {String} obj._callback 是否动态生成器
 * @param {Array<Object>} obj.positions 外围经纬度坐标
 * @param {Array<Object>} obj.holes 中间的洞的经纬度坐标
 * @returns
 */

export const polygonHierarchyItem = ({
  holes,
  positions,
  _callback,
  ...options
} = {}) => {
  return {
    _callback: Boolean(_callback),
    holes: holes || [],
    positions: positions || [],
    ...options,
    _generator: polygonHierarchy,
  };
};

export const polygonHierarchy = function () {
  let { _callback, positions, holes } = this;
  positions = setDefaultValue(positions, []);
  holes = setDefaultValue(holes, []);
  if (_callback) {
    return new CallbackProperty(() => {
      return new PolygonHierarchy(
        lngLatsToCartesian3Array(positions),
        lngLatsToCartesian3Array(holes)
      );
    }, false);
  }
  return new PolygonHierarchy(
    lngLatsToCartesian3Array(positions),
    lngLatsToCartesian3Array(holes)
  );
};

/**
 * @name 生成HPR
 * @param {Object} obj
 * @returns
 */

export const headingPitchRangeItem = ({
  heading,
  pitch,
  range,
  _callback,
  ...options
} = {}) => {
  return {
    heading: setDefaultValue(heading, 0),
    pitch: setDefaultValue(pitch, 0),
    range: setDefaultValue(range, 0),
    _callback: setDefaultValue(_callback, false),
    ...options,
    _generator: headingPitchRange,
  };
};

export const headingPitchRange = function () {
  const { _callback, heading, pitch, range } = this;
  if (_callback) {
    return new CallbackProperty(() => {
      return new HeadingPitchRange(
        Math.toRadians(obj.heading),
        Math.toRadians(obj.pitch),
        obj.range
      );
    }, false);
  }
  return new HeadingPitchRange(
    Math.toRadians(heading),
    Math.toRadians(pitch),
    Math.toRadians(range)
  );
};

/**
 * @name 生成长方体
 * @param {Object} obj
 * @returns
 */
export const rectangleItem = ({
  west,
  south,
  east,
  north,
  _callback,
  ...options
} = {}) => {
  return {
    west: setDefaultValue(west, 0),
    south: setDefaultValue(south, 0),
    east: setDefaultValue(east, 0),
    north: setDefaultValue(north, 0),
    ...options,
    _generator: rectangle,
  };
};

export const rectangle = function () {
  const { _callback, west, south, east, north } = this;
  if (_callback) {
    return new CallbackProperty(() => {
      return new Rectangle(
        Math.toRadians(obj.west),
        Math.toRadians(obj.south),
        Math.toRadians(obj.east),
        Math.toRadians(obj.north)
      );
    }, false);
  }
  return new Rectangle(
    Math.toRadians(west),
    Math.toRadians(south),
    Math.toRadians(east),
    Math.toRadians(north)
  );
};

/**
 * @name 生成缩放参数
 * @param {Object} obj
 * @returns
 */
export const nearFarScalarItem = ({ near, nearValue, far, farValue } = {}) => {
  return {
    near: setDefaultValue(near, 0),
    nearValue: setDefaultValue(nearValue, 0),
    far: setDefaultValue(far, 0),
    farValue: setDefaultValue(farValue, 0),
    _generator: nearFarScalar,
  };
};

export const nearFarScalar = function () {
  const { near, nearValue, far, farValue } = this;
  return new NearFarScalar(near, nearValue, far, farValue);
};

export const generate = (data) => {
  if (data?._generator) {
    return data._generator.call(data);
  } else if (!data instanceof Function && data instanceof Object) {
    return JSON.parse(JSON.stringify(data));
  } else {
    return data;
  }
};

export const mergeEntity = (options, entity) => {
  Object.keys(options).forEach((key) => {
    if (options[key]?.once && entity[key]) {
      return;
    }
    entity[key] = generate(options[key]);
  });
};

export const computeCircle = (radius) => {
  const positions = [];
  for (let i = 0; i < 360; i++) {
    const radians = cesiumMath.toRadians(i);
    positions.push(
      new Cartesian2(radius * Math.cos(radians), radius * Math.sin(radians))
    );
  }
  return positions;
};
